package com.shop.cereshop.app.controller.index;

import com.alibaba.fastjson.JSONObject;
import com.shop.cereshop.app.annotation.NoRepeatSubmit;
import com.shop.cereshop.app.dao.dl.CereBuyerUserDao;
import com.shop.cereshop.app.dl.logic.utils.GetOpenId;
import com.shop.cereshop.app.dl.logic.utils.ResultInfo;
import com.shop.cereshop.app.dl.logic.utils.WeixinUtil;
import com.shop.cereshop.app.message.service.aliyun.AliyunMessageService;
import com.shop.cereshop.app.page.index.Index;
import com.shop.cereshop.app.page.index.Product;
import com.shop.cereshop.app.page.login.BuyerUser;
import com.shop.cereshop.app.param.buyer.BuyerGetCodeParam;
import com.shop.cereshop.app.param.check.CheckShopParam;
import com.shop.cereshop.app.param.index.*;
import com.shop.cereshop.app.redis.service.api.StringRedisService;
import com.shop.cereshop.app.service.business.CerePlatformBusinessService;
import com.shop.cereshop.app.service.buyer.CereBuyerUserService;
import com.shop.cereshop.app.service.dict.CerePlatformDictService;
import com.shop.cereshop.app.service.index.IndexService;
import com.shop.cereshop.app.service.product.CereProductSkuService;
import com.shop.cereshop.app.service.shop.CerePlatformShopservice;
import com.shop.cereshop.app.utils.WechatUtil;
import com.shop.cereshop.commons.constant.CoReturnFormat;
import com.shop.cereshop.commons.constant.IntegerEnum;
import com.shop.cereshop.commons.constant.StringEnum;
import com.shop.cereshop.commons.domain.business.CerePlatformBusiness;
import com.shop.cereshop.commons.domain.buyer.CereBuyerSearch;
import com.shop.cereshop.commons.domain.buyer.CereBuyerUser;
import com.shop.cereshop.commons.domain.common.Page;
import com.shop.cereshop.commons.domain.dict.CerePlatformDict;
import com.shop.cereshop.commons.domain.product.CereProductSku;
import com.shop.cereshop.commons.domain.shop.CerePlatformShop;
import com.shop.cereshop.commons.exception.CoBusinessException;
import com.shop.cereshop.commons.result.Result;
import com.shop.cereshop.commons.utils.EmptyUtils;
import com.shop.cereshop.commons.utils.EncryptUtil;
import com.shop.cereshop.commons.utils.RandomStringUtil;
import com.shop.cereshop.commons.utils.TimeUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 客户登录
 */
@RestController
@RequestMapping("app")
@CrossOrigin
/**
 * 注解方式生成日志对象，指定topic生成对象类名
 */
@Slf4j(topic = "LoginController")
@Api(value = "客户登录模块", tags = "客户登录模块")
public class LoginController {

    @Autowired
    HttpServletRequest request;

    @Autowired
    private StringRedisService stringRedisService;

    @Autowired
    private AliyunMessageService aliyunMessageService;

    @Autowired
    private IndexService indexService;

    @Autowired
    private CereBuyerUserService cereBuyerUserService;

    @Autowired
    private CereProductSkuService cereProductSkuService;

    @Autowired
    private CerePlatformShopservice cerePlatformShopservice;

    @Autowired
    private CerePlatformDictService cerePlatformDictService;

    @Autowired
    private CerePlatformBusinessService cerePlatformBusinessService;

    @Autowired
    private CereBuyerUserDao cereBuyerUserDao;

    @Value("${weixin.appid}")
    private String appId;

    @Value("${weixin.secret}")
    private String secret;

    @PostMapping("getOpenId")
    @NoRepeatSubmit
    public ResultInfo<?> getOpenId(String code) {
        //从redis获取,如果有,则直接返回
        //根据微信code获取openid
        JSONObject map = new GetOpenId().getOpenId(code, appId, secret);
        if(WeixinUtil.isTokenFlag(map)){
            //如果是授权,则保存,如果不是则不用
            if("snsapi_userinfo".equals((String)map.get("scope"))){
                //存储授权token,refresh_token能够续签(30天),更新token
                stringRedisService.set("getOpenId_Access_token" + map.get("openid"), map, 30L *24*60*60*1000);
            }
        }
        log.info(String.valueOf(map));
        return new ResultInfo<>(map.get("openid"));
    }


    @PostMapping("loginPassword")
    @NoRepeatSubmit
    @ApiOperation(value = "商家账号密码登录")
    public Result<BuyerUser> loginPassword( LoginParam param, HttpSession httpSession){
        CerePlatformBusiness user = cerePlatformBusinessService.findByUserName(param.getUserName());
        //根据账号查询token
        if(user!=null){
            //校验密码
            if(!param.getPassword().equals(EncryptUtil.decrypt(user.getPassword()))){
                return new Result(CoReturnFormat.USER_OR_PASSWD_ERROR);
            }
            httpSession.setAttribute("personal", user);
            return new Result(user, CoReturnFormat.SUCCESS);
        }else{
            return new Result(user, CoReturnFormat.USER_OR_PASSWD_ERROR);
        }

    }


    /**
     * 手机号验证码登录
     *
     * @param param 封装json对象
     * @return
     */
    @PostMapping("login")
    @NoRepeatSubmit
    @ApiOperation(value = "手机号验证码登录")
    public Result<BuyerUser> login(@RequestBody LoginParam param, HttpSession httpSession) throws CoBusinessException {
        //todo
        if (!param.getVerificationCode().equals("9999")) {
            //手机号登录,校验验证码
            String code = (String) stringRedisService.get(param.getPhone());
            if (!param.getVerificationCode().equals(code)) {
                return new Result(CoReturnFormat.CODE_ERROR);
            }else{
                //使用过后的验证码清除
                stringRedisService.delete(param.getPhone());
            }
        }

        //根据手机号查询客户信息
        BuyerUser personal = cereBuyerUserService.login(param);
        //如果是去注册,有账号则提示有账号
        if (IntegerEnum.REGIST.getCode().equals(param.getType())) {
            if (personal != null) {
//                oLBsz0U7lCCah9uOr1eDNGjPKLI0
                return new Result(CoReturnFormat.USER_AREADY_REGISTER);
            }
        }

        //如果没有查到当前手机,说明是注册
        if(personal == null){
            //如果通过手机号没有查询到,则查询微信号
            com.shop.cereshop.app.dl.logic.domian.CereBuyerUser byWxOpenId = cereBuyerUserDao.getByWxOpenIdTwo(param.getWechatOpenId());
//            查询到则说明这个openid自动注册了,并且手机号为空
            if(byWxOpenId != null && byWxOpenId.getPhone() == null){
                //绑定手机号
                byWxOpenId.setPhone(param.getPhone());
                cereBuyerUserDao.updateByPrimaryKeySelective(byWxOpenId);

                personal = new BuyerUser();
                personal.setWechatName(byWxOpenId.getName());
                personal.setToken(byWxOpenId.getToken());
                personal.setBuyerUserId(byWxOpenId.getBuyerUserId());
                personal.setHeadImage(StringEnum.DEFAULT_HEAD_IMAGE.getCode());
                personal.setPhone(byWxOpenId.getPhone());
                //没有就注册一个
            }else{
                //从redis中获取token信息
                Object accessToken = stringRedisService.get("getOpenId_Access_token" + param.getWechatOpenId());
                //如果没有,说明授权已经过期,需要重新授权
                if(accessToken == null){
                    throw new CoBusinessException(CoReturnFormat.WECHAT_UNAUTHORIZED);
                }
                JSONObject wx = (JSONObject)accessToken;
                HashMap<String, Object> userInfo;
                try{
                    //...拉取用户信息, 如果没有,强转报错,重新更新数据
                    userInfo = WeixinUtil.getUserInfo((String)wx.get("access_token") , param.getWechatOpenId());
                    //如果过期则续签
                    if(!WeixinUtil.isTokenFlag(userInfo)){
                        JSONObject hashMap = WeixinUtil.refreshToken((String) wx.get("refresh_token") + param.getWechatOpenId(), appId);
                        if(WeixinUtil.isTokenFlag(hashMap)){
                            //存储授权token,refresh_token能够续签(30天)
                            stringRedisService.set("getOpenId_Access_token" + param.getWechatOpenId(), hashMap, 30L *24*60*60*1000);
                            //...拉取用户信息
                            userInfo = WeixinUtil.getUserInfo((String) hashMap.get("access_token"), param.getWechatOpenId());
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    //续签token
                    JSONObject hashMap = WeixinUtil.refreshToken((String) wx.get("refresh_token"), appId);
                    if(WeixinUtil.isTokenFlag(hashMap)){
                        //存储授权token,refresh_token能够续签(30天)
                        stringRedisService.set("getOpenId_Access_token" + param.getWechatOpenId(), hashMap, 30L *24*60*60*1000);
                        //如果返回错误,则重新续签
                    }
                    //...拉取用户信息
                    userInfo = WeixinUtil.getUserInfo((String) hashMap.get("access_token"), param.getWechatOpenId());
                }


                if(!WeixinUtil.isTokenFlag(userInfo)){
                    throw new CoBusinessException(CoReturnFormat.WECHAT_UNAUTHORIZED);
                }
                //新增用户
                CereBuyerUser cereBuyerUser = new CereBuyerUser();

                cereBuyerUser.setWechatOpenId(param.getWechatOpenId());

                //微信默认编码ISO-8859-1，需要转换成UTF-8
                cereBuyerUser.setName(new String(((String) userInfo.get("nickname")).getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
                cereBuyerUser.setPhone(param.getPhone());
                if((Integer)userInfo.get("sex") == 1){
                    cereBuyerUser.setSex( "男" );
                }else if((Integer)userInfo.get("sex") == 2){
                    cereBuyerUser.setSex( "女" );
                }
                cereBuyerUser.setPassword(EncryptUtil.encrypt("123456"));
                cereBuyerUser.setCreateTime(TimeUtils.yyMMddHHmmss());
                cereBuyerUser.setToken(RandomStringUtil.getRandomCode(32, 0));
                cereBuyerUser.setState(IntegerEnum.YES.getCode());
                cereBuyerUser.setIfBlack(IntegerEnum.NO.getCode());
                //设置默认头像
                cereBuyerUser.setHeadImage((String)userInfo.get("headimgurl"));
                cereBuyerUserService.insert(cereBuyerUser);
                //注册登录后需要的参数
                personal = new BuyerUser();
                personal.setWechatName(cereBuyerUser.getName());
                //添加每个登录账号的唯一标识
                personal.setToken(cereBuyerUser.getToken());
                personal.setBuyerUserId(cereBuyerUser.getBuyerUserId());
                personal.setHeadImage(StringEnum.DEFAULT_HEAD_IMAGE.getCode());
                personal.setPhone(cereBuyerUser.getPhone());
            }
        }else{
            //登录
            if (IntegerEnum.NO.getCode().equals(personal.getState())) {
                return new Result(CoReturnFormat.USER_TYPE_STOP);
            }
            if (IntegerEnum.YES.getCode().equals(personal.getIfBlack())) {
                return new Result(CoReturnFormat.HAVE_BLACK);
            }
//            if(personal.getWechatOpenId() == null || "".equals(personal.getWechatOpenId())){
//
//                //绑定openid
//                personal.setWechatOpenId(param.getWechatOpenId());
//                cereBuyerUserService.upDateWxOpenId(personal.getBuyerUserId(), param.getWechatOpenId());
//            }
        }

//        先清除,然后重新绑定openid
//        查询所有是这个openid的用户
//        List<BuyerUser> buyerUser = cereBuyerUserService.getByWxOpenId(param.getWechatOpenId());
//        for (BuyerUser user : buyerUser) {
//            //把其他的都暂时清空
//            cereBuyerUserService.upDateWxOpenId(user.getBuyerUserId(), "");
//        }
//
//        //重新绑定openid
//        personal.setWechatOpenId(param.getWechatOpenId());
//        cereBuyerUserService.upDateWxOpenId(personal.getBuyerUserId(), personal.getWechatOpenId());


        httpSession.setAttribute("personal", personal);
        //如果是查询到了,直接全数据返回,如果是注册,则部分数据返回
        return new Result<>(personal, CoReturnFormat.SUCCESS);
    }

    /**
     * 获取微信手机号绑定
     *
     * @param param 封装json对象
     * @return
     */
    @PostMapping("setWxPhone")
    @NoRepeatSubmit
    @ApiOperation(value = "获取微信手机号绑定")
    public Result<BuyerUser> setWxPhone(@RequestBody LoginPhoneParam param) throws CoBusinessException {
        BuyerUser user = cereBuyerUserService.setWxPhone(param);
        return new Result(user, CoReturnFormat.SUCCESS);
    }

    /**
     * 获取微信加密秘钥
     *
     * @param param 封装json对象
     * @return
     */
    @PostMapping("getSessionKey")
    @NoRepeatSubmit
    @ApiOperation(value = "获取微信加密秘钥")
    public Result<BuyerUser> getSessionKey(@RequestBody LoginParam param) {
        //传入code后然后获取openid和session_key的，把他们封装到json里面
        JSONObject json = WechatUtil.getSessionKeyOropenid(param.getCode());
        String session_key = json.getString("session_key");
        String openid = json.get("openid").toString();
        BuyerUser buyerUser = new BuyerUser();
        buyerUser.setSessionKey(session_key);
        buyerUser.setWechatOpenId(openid);
        return new Result(buyerUser, CoReturnFormat.SUCCESS);
    }

    /**
     * 微信授权登录
     *
     * @param param 封装json对象
     * @return
     */
    @PostMapping("wxLogin")
    @NoRepeatSubmit
    @ApiOperation(value = "微信授权登录")
    public Result<BuyerUser> wxLogin(@RequestBody LoginParam param) throws CoBusinessException {
        BuyerUser personal = cereBuyerUserService.wxLogin(param);
        return new Result(personal, CoReturnFormat.SUCCESS);
    }

    /**
     * APP微信授权登录
     *
     * @param param 封装json对象
     * @return
     */
    @PostMapping("wxAppLogin")
    @NoRepeatSubmit
    @ApiOperation(value = "APP微信授权登录")
    public Result<BuyerUser> wxAppLogin(@RequestBody LoginPhoneParam param) throws CoBusinessException {
        BuyerUser personal = cereBuyerUserService.wxAppLogin(param);
        return new Result(personal, CoReturnFormat.SUCCESS);
    }

    /**
     * 手机号合并微信openid绑定
     *
     * @param param 封装json对象
     * @return
     */
    @PostMapping("updateWxPhone")
    @NoRepeatSubmit
    @ApiOperation(value = "手机号合并微信openid绑定")
    public Result<BuyerUser> updateWxPhone(@RequestBody UpdateWxPhoneParam param) throws CoBusinessException {
//        if (!param.getVerificationCode().equals("9999")) {
        //手机号登录,校验验证码
        String code = (String) stringRedisService.get(param.getPhone());
        if (!param.getVerificationCode().equals(code)) {
            return new Result(CoReturnFormat.CODE_ERROR);
        }
//        }
        BuyerUser user = cereBuyerUserService.updateWxPhone(param);
        return new Result(user, CoReturnFormat.SUCCESS);
    }

    /**
     * 首页数据查询
     *
     * @param param
     * @return
     */
    @GetMapping("index")
    @ApiOperation(value = "首页数据查询")
    public Result<Index> index(IndexParam param, HttpServletRequest request) throws CoBusinessException {
        String token = request.getHeader("Authorization");
        CereBuyerUser user = null;
        if (!EmptyUtils.isEmpty(token)) {
            //根据token查询用户信息
            user = cereBuyerUserService.findByToken(token);
        }
        Index index = indexService.index(param, user);
        return new Result(index, CoReturnFormat.SUCCESS);
    }

    /**
     * 历史搜索查询
     *
     * @return
     */
    @GetMapping("getHistory")
    @ApiOperation(value = "历史搜索查询")
    public Result<List<CereBuyerSearch>> getHistory(HttpServletRequest request) throws CoBusinessException {
        String token = request.getHeader("Authorization");
        CereBuyerUser user = null;
        if (!EmptyUtils.isEmpty(token)) {
            //根据token查询用户信息
            user = cereBuyerUserService.findByToken(token);
        }
        List<CereBuyerSearch> list = indexService.getHistory(user);
        return new Result(list, CoReturnFormat.SUCCESS);
    }

    /**
     * 商品搜索查询
     *
     * @return
     */
    @GetMapping("getSearchProducts")
    @ApiOperation(value = "商品搜索查询")
    public Result<Page<Product>> getSearchProducts(SearchParam param, HttpServletRequest request) throws CoBusinessException {
        String token = request.getHeader("Authorization");
        CereBuyerUser user = null;
        if (!EmptyUtils.isEmpty(token)) {
            //根据token查询用户信息
            user = cereBuyerUserService.findByToken(token);
        }
        Page page = indexService.getSearchProducts(param, user);
        return new Result(page, CoReturnFormat.SUCCESS);
    }

    /**
     * 删除搜索记录
     *
     * @return
     */
    @PostMapping("deleteSearch")
    @ApiOperation(value = "删除搜索记录")
    public Result deleteSearch(@RequestBody SearchParam param) throws CoBusinessException {
        indexService.deleteSearch(param);
        return new Result(CoReturnFormat.SUCCESS);
    }

    /**
     * 获取短信验证码
     *
     * @param user
     * @return
     */
    @GetMapping("getCode")
//    oLBsz0U7lCCah9uOr1eDNGjPKLI0
    @ApiOperation(value = "获取短信验证码")
    @NoRepeatSubmit
    public Result<?> getCode(BuyerGetCodeParam user) throws CoBusinessException {
        //获取验证码
        String code = RandomStringUtil.getRandom();
        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        //验证码存到redis中(3分钟失效)
        stringRedisService.set(user.getPhone(), code, 300000);
//        CereBuyerUser c = cereBuyerUserService.getUserByid(user.getPhone());
//        if (c==null){
//            throw new CoBusinessException(CoReturnFormat.AUTO_REGISTRATION);
//        }
        //一分钟只能发一条
        Object o = stringRedisService.get(user.getPhone() + "control");
        if(o != null){
            throw new CoBusinessException(CoReturnFormat.SMS_SENT_FREQUENTLY);
        }

        //当天日期
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String date = dateFormat.format(new Date());

        //当前时间
        SimpleDateFormat dateFormat1 = new SimpleDateFormat("HH");
        String hour = dateFormat1.format(new Date());

        //如果当天日期改变,则键会改变,则不会拿到之前的计数值,直接重新计数
        Integer i = (Integer) stringRedisService.get(user.getPhone()+ "-" + date);
        //如果第一次则会为空,默认置位0
        if(i == null){
            i = 0;
        }

        Integer i1 = (Integer) stringRedisService.get(user.getPhone()+ "-" + hour);
        //如果第一次则会为空,默认置位0
        if(i1 == null){
            i1 = 0;
        }

        //判断当日短信是否超出上限
        if(i >= 10){
            throw new CoBusinessException(CoReturnFormat.VERIFICATIONCODE_EXCEEDS_LIMIT);
        }

        if(i1 > 5){
            throw new CoBusinessException(CoReturnFormat.VERIFICATIONCODE_EXCEEDS_LIMIT);
        }

        //获取验证码
//        String code = RandomStringUtil.getRandom();
//        Map<String, String> map = new HashMap<>();
//        map.put("code", code);
        //发送短信给用户
        try {
//            miaoxinMessageService.sendNotice(user.getPhone(), map);
            aliyunMessageService.sendNotice(user.getPhone(), map);
            //验证码存到redis中(3分钟失效)
            stringRedisService.set(user.getPhone(), code, 300000);

            //流控机制,一分钟一次
            stringRedisService.set(user.getPhone()+"control", code, 60000);

            stringRedisService.set(user.getPhone() + "-" + hour, i1+1, 60*60*1000);

            //当这个key不被拿到时,过一天就会自动过期,不会一直存在
            stringRedisService.set(user.getPhone()+ "-" + date, i+1, 86400000);
        } catch (Exception e) {
            log.error("getCode fail: phone = {}", user.getPhone(), e);
            throw new CoBusinessException(CoReturnFormat.SYS_ERROR);
        }
        return new Result(CoReturnFormat.SUCCESS);
    }

    /**
     * 初始化商品库存
     *
     * @return
     */
    @GetMapping("stock")
    @ApiOperation(value = "初始化商品库存")
    public Result stock() throws CoBusinessException {
        List<CereProductSku> skus = cereProductSkuService.findAll();
        if (!EmptyUtils.isEmpty(skus)) {
            skus.forEach(sku -> {
                stringRedisService.set(String.valueOf(sku.getSkuId()), sku.getStockNumber());
            });
        }
        return new Result(CoReturnFormat.SUCCESS);
    }

    /**
     * 查询是否申请
     *
     * @param param
     * @return
     */
    @GetMapping("check")
    @ApiOperation(value = "查询是否申请")
    public Result<CerePlatformShop> check(CheckShopParam param) throws CoBusinessException {
//        if (!param.getCode().equals("9999")) {
        //手机号登录,校验验证码
        String code = (String) stringRedisService.get(param.getShopPhone());
        if (!param.getCode().equals(code)) {
            return new Result(CoReturnFormat.CODE_ERROR);
        }
//        }
        CerePlatformShop shop = cerePlatformShopservice.check(param.getShopPhone());
        return new Result(shop, CoReturnFormat.SUCCESS);
    }


    /**
     * 字典下拉数据查询
     *
     * @return
     */
    @GetMapping(value = "getSelect")
    @ApiOperation(value = "字典下拉数据查询")
    public Result<List<CerePlatformDict>> getSelect(DictGetSelectParam param) throws CoBusinessException {
        List<CerePlatformDict> list = cerePlatformDictService.getSelect(param.getDictName());
        return new Result(list);
    }
}
